using AnimCollections;
using System.Runtime.CompilerServices;

namespace DA.AnimGraph {
    public static class TransitionUtility {
        public static int SumConditions(in TransitionDesc[] transitionDescs) {
            int sum = 0;
            foreach (var desc in transitionDescs) {
                sum += desc.conditions.Length;
            }
            return sum;
        }

        public unsafe static bool CreateCondition(out TransitionConditionLink link, in TransitionConditionDesc desc, ref GraphBuffer buffer) {
            switch (desc.conditionType) {
                case ConditionType.ExitTime: {
                        TransitionCondition_ExitTime.New(ref buffer, desc, out link);
                    }
                    return true;
                case ConditionType.Blackboard: {
                        TransitionCondition_Blackboard.New(ref buffer, desc, out link);
                    }
                    return true;
                default:
                    throw new System.Exception($"Unknown Condition Type :{desc.conditionType}");
            }
        }

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        private unsafe static T* Malloc<T>(ref GraphBuffer buffer) where T : unmanaged {
            var t = buffer.Malloc<T>();
            *t = new();
            return t;
        }
    }


    internal static class TransitionConditionConstructure {
        public unsafe static void New<T>(out TransitionConditionLink link, out T* condPtr, ref GraphBuffer buffer, in TransitionConditionDesc desc) where T : unmanaged {
            link = new TransitionConditionLink(desc.conditionType);

            condPtr = buffer.Malloc<T>();
            *condPtr = new();
            
            link.perkType = AGRuntimeTypeRegister.GetInstance().GetEnumByType(typeof(T));
        }
    }

    public unsafe partial struct TransitionCondition_ExitTime {
        public static void New(ref GraphBuffer buffer, in TransitionConditionDesc desc, out TransitionConditionLink link) {
            TransitionConditionConstructure.New(out link, out TransitionCondition_ExitTime* condPtr, ref buffer, desc);
            SetupFunction(ref link);
            SetupLink(condPtr, ref link);
            condPtr->Setup(desc);
        }
        public static void SetupFunction(ref TransitionConditionLink link) {
            link.virtualFunction = AGRuntimeTypeRegister.GetInstance().GetTransitionConditionVirtualTable(AGRuntimeType.TransitionCondition_ExitTime);
            //link.CheckFunction = CachedEvaluate;
        }
        public static TransitionConditionVirtualTable GetVirtualFunction() {
            var vt = new TransitionConditionVirtualTable();
            vt.CheckFunction = CachedEvaluate;
            return vt;
        }
        internal static readonly TransitionConditionLink.CheckDelegate CachedEvaluate = Check;
    }

    public unsafe partial struct TransitionCondition_Blackboard {
        public static void New(ref GraphBuffer buffer, in TransitionConditionDesc desc, out TransitionConditionLink link) {
            TransitionConditionConstructure.New(out link, out TransitionCondition_Blackboard* condPtr, ref buffer, desc);
            SetupFunction(ref link);
            SetupLink(condPtr, ref link);
            condPtr->Setup(desc);
        }
        public static void SetupFunction(ref TransitionConditionLink link) {
            link.virtualFunction = AGRuntimeTypeRegister.GetInstance().GetTransitionConditionVirtualTable(AGRuntimeType.TransitionCondition_Blackboard);
            //link.CheckFunction = CachedEvaluate;
        }
        public static TransitionConditionVirtualTable GetVirtualFunction() {
            var vt = new TransitionConditionVirtualTable();
            vt.CheckFunction = CachedEvaluate;
            return vt;
        }
        internal static readonly TransitionConditionLink.CheckDelegate CachedEvaluate = Check;
    }

}
